package cn.calm.xhtml.spring;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.servlet.view.AbstractTemplateView;

import cn.calm.xhtml.api.Template;
import cn.calm.xhtml.api.TemplateEngine;
import cn.calm.xhtml.api.exception.XhtmlException;
import cn.calm.xhtml.api.service.ResponseWriter;
import cn.calm.xhtml.api.service.XhtmlContext;

public class XhtmlView extends AbstractTemplateView {
	private static final Logger logger = LoggerFactory
			.getLogger(XhtmlView.class);
	private TemplateEngine engine;
	private Template template;
	private ApplicationContext context;
	@SuppressWarnings("unchecked")
	@Override
	protected void renderMergedTemplateModel(Map<String, Object> model,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		long currentTimeMillis = System.currentTimeMillis();
		ResponseWriter writer = new ResponseWriter(response.getWriter());
		XhtmlContext xhtmlContext = context.getBean(XhtmlContext.class);
		xhtmlContext.setResponseWriter(writer);
		xhtmlContext.setTemplateEngine(engine);
		xhtmlContext.setAllValue(model);
		Enumeration<String> attributeNames = request.getAttributeNames();
		Map<String, Object> scope = new HashMap<String, Object>();
		while (attributeNames.hasMoreElements()) {
			String nextElement = attributeNames.nextElement();
			scope.put(nextElement, request.getAttribute(nextElement));
		}
		xhtmlContext.setValue("requestScope", scope);
		scope = new HashMap<String, Object>();
		Map<String,?> parameterMap = request.getParameterMap();
		for(Map.Entry<String, ?>en:parameterMap.entrySet()){
			Object value = en.getValue();
			String va;
			if(value instanceof Object[]){
				va= StringUtils.join((Object[])value);
			}else{
				va=value.toString();
			}
			va=new String(va.getBytes("ISO8859-1"),"UTF-8");
			scope.put(en.getKey(), va);
		}
		
		xhtmlContext.setValue("requestParameter", scope);
		
		HttpSession session = request.getSession();
		attributeNames = session.getAttributeNames();
		scope = new HashMap<String, Object>();
		while (attributeNames.hasMoreElements()) {
			String nextElement = attributeNames.nextElement();
			scope.put(nextElement, session.getAttribute(nextElement));
		}
		xhtmlContext.setValue("sessionScope", scope);
		xhtmlContext.setValue("session", session);
		ServletContext servletContext = session.getServletContext();
		attributeNames = servletContext.getAttributeNames();
		scope = new HashMap<String, Object>();
		while (attributeNames.hasMoreElements()) {
			String nextElement = attributeNames.nextElement();
			scope.put(nextElement, servletContext.getAttribute(nextElement));
		}
		xhtmlContext.setValue("message",
				model.get(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE));
		xhtmlContext.setValue("applicationScope", scope);
		xhtmlContext.setValue("application", servletContext);
		template.render(xhtmlContext);
		logger.info("using " + (System.currentTimeMillis() - currentTimeMillis));
	}
	@Override
	protected void initApplicationContext(ApplicationContext context) {
		super.initApplicationContext(context);
		this.context = context;
		if (engine == null) {
			engine= context.getBean(TemplateEngine.class);
		}
	}

	/**
	 * Check whether the underlying resource that the configured URL points to
	 * actually exists.
	 * 
	 * @param locale
	 *            the desired Locale that we're looking for
	 * @return {@code true} if the resource exists (or is assumed to exist);
	 *         {@code false} if we know that it does not exist
	 * @throws Exception
	 *             if the resource exists but is invalid (e.g. could not be
	 *             parsed)
	 */
	public boolean checkResource(Locale locale) throws Exception {
		try {
			template = engine.getTemplate(getUrl());
			return true;
		} catch (XhtmlException e) {
			return false;
		}
	}

	public TemplateEngine getEngine() {
		return engine;
	}

	public void setEngine(TemplateEngine engine) {
		this.engine = engine;
	}

}
